package fp.poczadly.client.presenter;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.cellview.client.AbstractHasData;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;

import fp.poczadly.client.LiveChatServiceAsync;
import fp.poczadly.client.event.LoginEvent;
import fp.poczadly.client.event.LogoutEvent;
import fp.poczadly.client.event.PrivateMessageEvent;
import fp.poczadly.client.event.ReceivePrivateMessageEvent;
import fp.poczadly.shared.Message;
import fp.poczadly.shared.User;
import fp.poczadly.shared.Utils;

public class ChatPresenter implements Presenter {

	public interface Display {
		public AbstractHasData<String> messageList();
		public AbstractHasData<String> userList();
		public void setMessageListData( List<String> data );
		public HasValue<String> messageTextField();
		public HasClickHandlers sendMessageButton();
		public HasClickHandlers logoutButton();
		Widget asWidget();
	}

	private final LiveChatServiceAsync rpcService;
	private HandlerManager eventBus;
	private Display display;

	private User user;
	private List<String> messageList = new ArrayList<String>();
	private List<String> userList = new ArrayList<String>();

	private static boolean privMessage;
	
	public ChatPresenter( LiveChatServiceAsync rpcService,
			HandlerManager eventBus, User user, Display display ) {
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.user = user;
		this.display = display;
	}

	public void bind() {
		display.sendMessageButton().addClickHandler( new ClickHandler() {

			public void onClick( ClickEvent event ) {
				sendMessage();
			}
		} );

		display.logoutButton().addClickHandler( new ClickHandler() {

			public void onClick( ClickEvent event ) {
				logout();
			}
		} );

		addTimer();

		setSelectionModel();
	}

	private void setSelectionModel() {
		final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();

		display.userList().setSelectionModel( selectionModel );

		selectionModel.addSelectionChangeHandler( new SelectionChangeEvent.Handler() {
			public void onSelectionChange( SelectionChangeEvent event ) {
				String selected = selectionModel.getSelectedObject();
				if( selected != null ) {
					eventBus.fireEvent( new PrivateMessageEvent( selected ) );
				}
			}
		} );
	}

	private void addTimer() {
		final Timer timer = new Timer() {

			@Override
			public void run() {
				rpcService.checkSession( Utils.USER, new AsyncCallback<User>() {

					@Override
					public void onSuccess( User result ) {
						if( receiveMessages() != null ) {
							display.messageList().setRowData( 0, receiveMessages() );
						}
						if( getAllUsers() != null ) {
							display.userList().setRowData( 0, getAllUsers() );
							
							rpcService.receivePrivateMessages( user, new AsyncCallback<List<Message>>() {
								
								@Override
								public void onFailure( Throwable caught ) {}
								
								@Override
								public void onSuccess( List<Message> result ) {
									if( !isPrivMessage() ) {
										eventBus.fireEvent( new ReceivePrivateMessageEvent( user ) );
									}
								}
							} );
						}
					}

					@Override
					public void onFailure( Throwable caught ) {
						eventBus.fireEvent( new LoginEvent( null ) );
					}
				} );
				
			}
		};

		timer.scheduleRepeating( Utils.SCHEDULE_TIME );
	}

	@Override
	public void go( HasWidgets container ) {
		bind();

		container.clear();
		container.add( display.asWidget() );
	}

	public void sendMessage() {
		Message message = new Message( user, display.messageTextField().getValue() );

		rpcService.sendMessage( message, new AsyncCallback<Void>() {

			@Override
			public void onFailure( Throwable caught ) {
				Window.alert( Utils.CANNOT_SEND_MESSAGE );
			}

			@Override
			public void onSuccess( Void result ) {}
		});
		
		display.messageTextField().setValue( "" );
	}

	public List<String> receiveMessages() {
		rpcService.receiveMessages( new AsyncCallback<List<Message>>() {

			@Override
			public void onSuccess( List<Message> result ) {
				messageList.clear();
				
				for( Message message : result ) {
					messageList.add( message.toString() );
				}
			}

			@Override
			public void onFailure( Throwable caught ) {
				Window.alert( Utils.CANNOT_RECEIVE_MESSAGES );
			}
		} );

		return messageList;
	}

	public List<String> getAllUsers() {
		rpcService.getAllUsers( new AsyncCallback<List<String>>() {

			@Override
			public void onFailure( Throwable caught ) {
				Window.alert( Utils.CANNOT_SEE_OTHER_USERS );
			}

			@Override
			public void onSuccess( List<String> result ) {
				userList = result;
			}
		} );

		return userList;
	}

	public void logout() {
		rpcService.removeUser( user, new AsyncCallback<User>() {

			@Override
			public void onFailure( Throwable caught ) {
				Window.alert( Utils.CANNOT_LOG_OUT );
			}

			@Override
			public void onSuccess( User result ) {
				eventBus.fireEvent( new LogoutEvent( result ) );
			}
		} );
	}

	public static boolean isPrivMessage() {
		return privMessage;
	}

	public static void setPrivMessage( boolean privMessage ) {
		ChatPresenter.privMessage = privMessage;
	}
}
